package com.katesoft.scale4j.rttp.spring.postprocessor;

import com.katesoft.scale4j.log.Logger;
import com.katesoft.scale4j.log.LogFactory;
import com.katesoft.scale4j.persistent.hibernate.EventListeners;
import com.katesoft.scale4j.persistent.model.RevisionDomainEntity;
import com.katesoft.scale4j.persistent.model.unified.BO;
import com.katesoft.scale4j.persistent.spring.postprocessor.HibernateSessionExtensionPostProcessor;
import com.katesoft.scale4j.rttp.hibernate.ClusteredIncrementGenerator;
import com.katesoft.scale4j.rttp.subscription.CloudSubscriber;
import org.hibernate.HibernateException;
import org.hibernate.event.SaveOrUpdateEvent;
import org.hibernate.event.SaveOrUpdateEventListener;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import static com.katesoft.scale4j.common.spring.IPostProcessingOrder.RTTP_HIBERNATE_POST_PROCESSOR;

/**
 * This is internal class(will add hibernate event listener for assigning entities id)
 *
 * @author kate2007
 */
public class RttpHibernatePostProcessor extends HibernateSessionExtensionPostProcessor
{
    private transient Logger logger = LogFactory.getLogger(getClass());
    private transient ClusteredIncrementGenerator idGenerator;
    //
    private Boolean generateSchemaUpdateScript;
    private Boolean generateSchemaCreateScript;
    private Boolean generateSchemaDropScript;

    public RttpHibernatePostProcessor()
    {
        setOrder(RTTP_HIBERNATE_POST_PROCESSOR);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
    {
        if (beanProperties == null) {
            beanProperties = new Properties();
        }
        final CloudSubscriber cloudSubscriber = idGenerator.getBridge().getCloudSubscriber();
        //
        Map<String, Object> listeners = new HashMap<String, Object>()
        {{
                Collection c = Collections.singleton(new SaveOrUpdateEventListener()
                {
                    @Override
                    public void onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException
                    {
                        if (event.getObject() instanceof BO) {
                            BO bo = (BO) event.getObject();
                            if (bo.getUniqueIdentifier() == null) {
                                long uniqueIdentifier = idGenerator.generate(bo);
                                logger.debug("identifier %s generated for IBO %s", uniqueIdentifier, bo.getPersistentClass().getSimpleName());
                                bo.setUniqueIdentifier(uniqueIdentifier);
                            }
                        }
                        else if (event.getObject() instanceof RevisionDomainEntity) {
                            RevisionDomainEntity entity = (RevisionDomainEntity) event.getObject();
                            if (entity.getUniqueIdentifier() == null) {
                                long uniqueIdentifier = idGenerator.generate(entity);
                                logger.debug("revision %s generated for %s", uniqueIdentifier, entity.getClass().getSimpleName());
                                entity.setUniqueIdentifier(uniqueIdentifier);
                            }
                        }
                    }
                });
                put(EventListeners.POST_INSERT, Collections.singleton(cloudSubscriber));
                put(EventListeners.POST_UPDATE, Collections.singleton(cloudSubscriber));
                put(EventListeners.POST_DELETE, Collections.singleton(cloudSubscriber));
                put(EventListeners.SAVE, c);
                put(EventListeners.SAVE_UPDATE, c);
            }};
        beanProperties.put("eventListeners", listeners);
        //
        if (generateSchemaUpdateScript != null) { beanProperties.put("generateSchemaUpdateScript", generateSchemaUpdateScript); }
        if (generateSchemaCreateScript != null) { beanProperties.put("generateSchemaCreateScript", generateSchemaCreateScript); }
        if (generateSchemaDropScript != null) { beanProperties.put("generateSchemaDropScript", generateSchemaDropScript); }
        //
        super.postProcessBeanFactory(configurableListableBeanFactory);
        logger.debug("cloud subscription %s was added", cloudSubscriber);
    }

    /**
     * set cluster aware id generator.
     *
     * @param idGenerator cluster aware id generator.
     */
    @Required
    public void setIdGenerator(ClusteredIncrementGenerator idGenerator)
    {
        this.idGenerator = idGenerator;
    }

    public void setGenerateSchemaUpdateScript(boolean generateSchemaUpdateScript)
    {
        this.generateSchemaUpdateScript = generateSchemaUpdateScript;
    }

    public void setGenerateSchemaCreateScript(boolean generateSchemaCreateScript)
    {
        this.generateSchemaCreateScript = generateSchemaCreateScript;
    }

    public void setGenerateSchemaDropScript(boolean generateSchemaDropScript)
    {
        this.generateSchemaDropScript = generateSchemaDropScript;
    }
}
